#include "memorymanager.h"
#include "system.h"

MemoryManager::MemoryManager()
{
	// Allocate space for an array of bools
	// Zero it out to show that all pages are initially available
    swapPageInUse = new bool[NUM_SWAP_PAGES];
	for(int i=0; i<NUM_SWAP_PAGES; i++)
		swapPageInUse[i] = false;

	numPhysicalPages = MEM_SIZE / PageSize;
	physicalPageInUse = new bool[numPhysicalPages];
	for(int i=0; i<numPhysicalPages; i++)
		physicalPageInUse[i] = false;
	
	// Create or open the swap file
	char swapFileName[] = "swapfile";
	swapFile = fileSystem->Open(swapFileName);
	if(swapFile == NULL)
	{
		int initialSize = 0; // TODO
		fileSystem->Create(swapFileName, initialSize);
		swapFile = fileSystem->Open(swapFileName);
		if(swapFile == NULL)
		{
			ASSERT(false);
		}		
	}
}

int MemoryManager::allocateSwapPage()
{
    for(int i=0; i<NUM_SWAP_PAGES; i++)
    {
        // Find a free page
        if(!swapPageInUse[i])
        {
            // Mark the page as taken and return it
            swapPageInUse[i] = true;

            return i;
        }

    }
   

 	// No pages were available
	return MM_ALLOCATION_FAILED;
}

void MemoryManager::releasePage(int i, int physicalPage)
{
	swapPageInUse[i] = false;
	if(physicalPage != -1)
		physicalPageInUse[physicalPage] = false;	
}

int	MemoryManager::getSwapPageLocation(int swapPageIndex)
{
	int pageOffset;
	// The offset between pages in the swap file is just the size of the page
	pageOffset = PageSize;

	return pageOffset*swapPageIndex;
}

MemoryManager::~MemoryManager()
{
	delete [] physicalPageInUse;
    delete [] swapPageInUse;

}

void MemoryManager::copyPageFromSwap(int fromSwapPage, int toSwapPage)
{
	char buffer[PageSize];
	int readAt = getSwapPageLocation(fromSwapPage);
	int writeAt = getSwapPageLocation(toSwapPage);

	// Read the page from the first processes swap page
	swapFile->ReadAt( buffer, PageSize, readAt);
	// Write it to the forked processes swap page
	swapFile->WriteAt( buffer, PageSize, writeAt);
}



void MemoryManager::writePage(int physicalPage, int swapPage)
{
	int writeAt = getSwapPageLocation(swapPage);
	int readAt = physicalPage * PageSize;
	swapFile->WriteAt( &(machine->mainMemory[readAt]) , PageSize, writeAt);
}

void MemoryManager::loadPage(int physicalPage, int swapPage)
{
	int writeAt = physicalPage * PageSize;
	int readAt = getSwapPageLocation(swapPage);

	swapFile->ReadAt( &(machine->mainMemory[writeAt]) , PageSize, readAt );
}

int MemoryManager::allocatePhysicalPage()
{
    for(int i=0; i<numPhysicalPages; i++)
    {
        // Find a free page
        if(!physicalPageInUse[i])
        {
            // Mark the page as taken and return it
            physicalPageInUse[i] = true;
            return i;
        }

    }
    // No pages were available
    return MM_ALLOCATION_FAILED;

}

void MemoryManager::writeBufferToSwapPage(char *buffer, int swapPage)
{
	int writeAt = getSwapPageLocation(swapPage);	
	swapFile->WriteAt(buffer, PageSize, writeAt);
}






















